package org.dromara.mall.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpStatus;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.BeanUtils;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.mall.domain.TerMallCart;
import org.dromara.mall.domain.TerMallOrderitem;
import org.dromara.mall.domain.TerMallRegional;
import org.dromara.mall.domain.bo.TerMallCartBo;
import org.dromara.mall.domain.bo.TerMallOrderitemBo;
import org.dromara.mall.domain.bo.TerMallProductBo;
import org.dromara.mall.domain.enums.MallStatusContent;
import org.dromara.mall.domain.vo.*;
import org.dromara.mall.service.*;
import org.dromara.mall.util.HybridCodeUtil;
import org.dromara.tearoom.api.RemoteAppUserService;
import org.dromara.tearoom.api.RemoteCouponService;
import org.dromara.tearoom.api.RemotePayService;
import org.dromara.tearoom.api.domain.bo.RemoteHtlOrderBo;
import org.dromara.tearoom.api.domain.bo.RemotePayCommonBo;
import org.dromara.tearoom.api.domain.vo.RemoteHtlOrderVo;
import org.dromara.tearoom.api.domain.vo.RemotePayVo;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.dromara.mall.domain.bo.TerMallOrderBo;
import org.dromara.mall.domain.TerMallOrder;
import org.dromara.mall.mapper.TerMallOrderMapper;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 订单主信息Service业务层处理
 *
 * @author xch
 * @date 2025-06-27
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class TerMallOrderServiceImpl implements ITerMallOrderService {

    private final TerMallOrderMapper baseMapper;
    private final ITerMallCartService cartService;
    private final ITerMallOrderitemService orderitemService;
    private final ITerMallProductService mallProductService;
    private final ITerFullSyncService fullSyncService;
    private final  ITerMallRegionalService terMallRegionalService;

    @DubboReference
    private RemotePayService remotePayService;
    @DubboReference
    private RemoteCouponService remoteCouponService;

    @DubboReference
    private RemoteAppUserService remoteAppUserService;
    private static final RedissonClient CLIENT = SpringUtils.getBean(RedissonClient.class);
    /**
     * 查询订单主信息
     *
     * @param id 主键
     * @return 订单主信息
     */
    @Override
    public TerMallOrderVo queryById(String id){
        return baseMapper.selectVoById(id);
    }

    /**
     * 分页查询订单主信息列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 订单主信息分页列表
     */
    @Override
    public TableDataInfo<TerMallOrderVo> queryPageList(TerMallOrderBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<TerMallOrder> lqw = buildQueryWrapper(bo);
        Page<TerMallOrderVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }
    @Override
    public TableDataInfo<TerMallOrderVo> queryOrderList(TerMallOrderBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<TerMallOrder> lqw = buildQueryWrapper(bo);
        Page<TerMallOrderVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        TableDataInfo<TerMallOrderVo>  orders = TableDataInfo.build(result);
        orders.getRows().forEach(order -> {
            TerMallOrderitemBo item = new TerMallOrderitemBo();
            item.setOrderId(order.getId());
            order.setProducts(orderitemService.queryList(item));
            if(order.getPickupPointId()!=null){
                TerMallRegionalVo regionalVo= terMallRegionalService.queryById(order.getPickupPointId());
                order.setPickupPoint(regionalVo.getGroupName());
                order.setTelephone(regionalVo.getPhone());
                order.setPickupAddress(regionalVo.getAddress());
            }
        });
        return orders;
    }
    /**
     * 查询符合条件的订单主信息列表
     *
     * @param bo 查询条件
     * @return 订单主信息列表
     */
    @Override
    public List<TerMallOrderVo> queryList(TerMallOrderBo bo) {
        LambdaQueryWrapper<TerMallOrder> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<TerMallOrder> buildQueryWrapper(TerMallOrderBo bo) {
        LambdaQueryWrapper<TerMallOrder> lqw = Wrappers.lambdaQuery();
        lqw.orderByDesc(TerMallOrder::getCreateTime);
        lqw.eq(StringUtils.isNotBlank(bo.getOrderNo()), TerMallOrder::getOrderNo, bo.getOrderNo());
        lqw.eq(bo.getUserId() != null, TerMallOrder::getUserId, bo.getUserId());
        lqw.eq(bo.getPaymentMethod() != null, TerMallOrder::getPaymentMethod, bo.getPaymentMethod());
        lqw.eq(bo.getOrderStatus() != null, TerMallOrder::getOrderStatus, bo.getOrderStatus());
        lqw.eq(StringUtils.isNotBlank(bo.getConsignee()), TerMallOrder::getConsignee, bo.getConsignee());
        lqw.eq(StringUtils.isNotBlank(bo.getMobile()), TerMallOrder::getMobile, bo.getMobile());
        lqw.eq(StringUtils.isNotBlank(bo.getAddress()), TerMallOrder::getAddress, bo.getAddress());
        lqw.eq(bo.getPickupPointId() != null, TerMallOrder::getPickupPointId, bo.getPickupPointId());
        lqw.eq(StringUtils.isNotBlank(bo.getPickupCode()), TerMallOrder::getPickupCode, bo.getPickupCode());
        return lqw;
    }

    /**
     * 新增订单主信息
     *
     * @param bo 订单主信息
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(TerMallOrderBo bo) {
        TerMallOrder add = MapstructUtils.convert(bo, TerMallOrder.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改订单主信息
     *
     * @param bo 订单主信息
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(TerMallOrderBo bo) {
        TerMallOrder update = MapstructUtils.convert(bo, TerMallOrder.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(TerMallOrder entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除订单主信息信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public TerCreateVo createCartOrder(TerMallOrderBo bo){
        TerMallCartBo CartBo = new TerMallCartBo();
        CartBo.setUserId(LoginHelper.getAppLoginUser()!=null?LoginHelper.getAppLoginUser().getId():bo.getUserId());
        List<TerMallCartVo> cartVoList = cartService.queryList(CartBo);
        if(cartVoList==null || cartVoList.size()<1){
            throw new ServiceException("购物车无记录！");
        }
        String OrderId=generateOrderId();
        bo.setId(OrderId);
        TerMallOrderitemBo itemBo =null;
        for(TerMallCartVo cartVo : cartVoList){
            if(cartVo.getSelected()==1){
                TerMallProductVo product = syncInventory(cartVo.getProductId(),cartVo.getQuantity());
                itemBo = new TerMallOrderitemBo();
                itemBo.setPrice(product.getPrice());
                itemBo.setQuantity(cartVo.getQuantity());
                itemBo.setOrderId(OrderId);
                itemBo.setProductId(product.getId());
                itemBo.setProductName(product.getName());
                itemBo.setTotalPrice(product.getPrice()*cartVo.getQuantity());
                itemBo.setThumbnail(product.getThumbnail());
                orderitemService.insertByBo(itemBo);
            }
        }
        TerCreateVo vo = new TerCreateVo();
        bo.setIsCart(1);
        vo.setId(create(bo));
        return  vo;
    };
    @Transactional(rollbackFor = Exception.class)
    @Override
    public TerCreateVo createOrder(TerMallOrderBo bo){
        if(bo.getProductId()==null){
            throw new ServiceException("产品id不能为空");
        }
        String OrderId=generateOrderId();
        bo.setId(OrderId);
        TerMallProductVo product = syncInventory(bo.getProductId(),bo.getQuantity());
        TerMallOrderitemBo itemBo = new TerMallOrderitemBo();
        itemBo.setPrice(product.getPrice());
        itemBo.setQuantity(bo.getQuantity());
        itemBo.setOrderId(OrderId);
        itemBo.setProductId(product.getId());
        itemBo.setProductName(product.getName());
        itemBo.setTotalPrice(product.getPrice()*bo.getQuantity());
        itemBo.setThumbnail(product.getThumbnail());
        orderitemService.insertByBo(itemBo);
        TerCreateVo vo = new TerCreateVo();
        bo.setIsCart(0);
        vo.setId(create(bo));
        return  vo;
    }

    private TerMallProductVo syncInventory(Long productId, Integer quantity){
        if (!fullSyncService.deductInventory(productId, quantity)) {
            throw new ServiceException("库存不足");
        }
        return updateDbInventory( productId, quantity);
    }

    private String create(TerMallOrderBo bo){
        bo.setUserId(LoginHelper.getAppLoginUser()!=null?LoginHelper.getAppLoginUser().getId():bo.getUserId());
        //更新预计收入
        RemoteHtlOrderVo rvo= remoteCouponService.calculatePrice(BeanUtils.toBean(bo, RemoteHtlOrderVo.class));
        BeanUtils.copyProperties(rvo, bo);
        String mobile= remoteAppUserService.selectPhoneById(LoginHelper.getAppLoginUser().getId());
        bo.setMobile(mobile);
        if(insertByBo(bo)){
            return bo.getId();
        }else{
            return null;
        }
    }

    private TerMallProductVo updateDbInventory(Long productId, Integer quantity) {
        RLock lock = CLIENT.getLock("inventory:db-update:" + productId);
        try {
            if (lock.tryLock(10, 30, TimeUnit.SECONDS)) {
                TerMallProductVo product= mallProductService.queryById(productId);
                TerMallProductBo bo = new TerMallProductBo();
                bo.setId(productId);
                bo.setStock(product.getStock()-quantity);
                bo.setSales(product.getSales()!=null?product.getSales()+quantity:quantity);
                bo.setVersion(product.getVersion());
                if(mallProductService.updateByBo(bo))return product;
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new ServiceException("库存更新冲突");
        } finally {
            lock.unlock();
        }
        return null;
    }


    @Override
    public TerPayVo payOrder(TerMallOrderBo bo){
        TerMallOrder  order= BeanUtils.toBean(bo, TerMallOrder.class);
        RemotePayVo rpv=  remotePayService.pay(BeanUtils.toBean(bo, RemotePayCommonBo.class));
        TerPayVo payVo=BeanUtils.toBean(rpv, TerPayVo.class);
        if(ObjectUtil.isNotEmpty(payVo)&&payVo.getCode()== HttpStatus.HTTP_OK){
            TerMallOrder update=new TerMallOrder();
            TerMallRegionalVo vo = terMallRegionalService.queryById(bo.getPickupPointId());
            update.setPickupPointId(bo.getPickupPointId());
            update.setId(order.getId());
            update.setPaymentMethod(payVo.getPayMethod());
            update.setUpdateTime(LocalDateTime.now());
            if(StringUtils.isNotBlank(bo.getConsignee()))update.setConsignee(bo.getConsignee());
            if(StringUtils.isNotBlank(bo.getMobile()))update.setMobile(bo.getMobile());
            order.setUpdateTime(update.getUpdateTime());
            baseMapper.updateById(update);
        }
        payVo.setData(order);
        return payVo;
    }
    public String generateOrderId() {
        SimpleDateFormat sdf = new SimpleDateFormat("MMddHHmmss");
        String date = sdf.format(new Date());
        String sequence = String.format("%06d", new Random().nextInt(999999));
        String suffix = RandomStringUtils.randomAlphanumeric(4); // 4位随机字母数字
        return String.format("MAL-%s%s%s", date, sequence, suffix);

    }

    @Override
    public String getPickupCode(TerMallOrderBo bo){
        String mobile= remoteAppUserService.selectPhoneById(LoginHelper.getAppLoginUser().getId());
        TerMallOrder update=new TerMallOrder();
        update.setId(bo.getId());
        update.setPickupCode(HybridCodeUtil.generate(mobile));
        baseMapper.updateById(update);
        return update.getPickupCode();
    }

    @Override
    public Boolean refund(TerMallOrderBo bo){
        String refundId=  remotePayService.refund(BeanUtils.toBean(bo, RemoteHtlOrderBo.class));
        TerMallOrder update=new TerMallOrder();
        update.setId(bo.getId());
        update.setOrderStatus(MallStatusContent.REFUND);
        update.setRefundId(refundId);
        update.setUpdateTime(LocalDateTime.now());
        return baseMapper.updateById(update)>0;
    }
}
